﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Drawing;
namespace BioImg
{
    public delegate void CallbackDelegate(float progress, ref int state, [MarshalAs(UnmanagedType.LPStr)] StringBuilder message, int outerID);
    //typedef void (__stdcall* CallbackFunction) (float progress, int state, const char* message);
    public class ImageEngine
    {
        const string dllpath = @"DLL\ImageViewerEngine.dll";
        /// <summary>
        /// 获取图片宽高
        /// </summary>
        /// <param name="ID"></param>
        /// <param name="w"></param>
        /// <param name="h"></param>
        /// <returns></returns>
        [DllImport(dllpath, EntryPoint = "openslide_get_level0_dimensions", CallingConvention = CallingConvention.Cdecl)]
        public static extern int openslide_get_level0_dimensions(int ID, ref int w, ref int h);

        //DLL_IMAGE_VIEWER_ENGINE_OPENSLIDE_API 
        [DllImport(dllpath, EntryPoint = "openslide_get_level_count", CallingConvention = CallingConvention.Cdecl)]
        public static extern int openslide_get_level_count(int ID);

        //DLL_IMAGE_VIEWER_ENGINE_OPENSLIDE_API 
        [DllImport(dllpath, EntryPoint = "openslide_close", CallingConvention = CallingConvention.Cdecl)]
        public static extern void openslide_close(int ID);



        [DllImport(dllpath, EntryPoint = "openslide_open", CallingConvention = CallingConvention.Cdecl)]
        public static extern int openslide_open(string imageFolder,ref int ID);

        [DllImport(dllpath, EntryPoint = "openslide_init", CallingConvention = CallingConvention.Cdecl)]
        public static extern int openslide_init(int ID);

        //获取某一块数据 与openseadragon对接
        //DLL_IMAGE_VIEWER_ENGINE_API
        [DllImport(dllpath, EntryPoint = "GetImageTile", CallingConvention = CallingConvention.Cdecl)]
        public static extern int GetImageTile(int layer, int col, int row, int tileSize, byte[] jpegBuffer,  int[]  buffSize, int ID);


       
        //public static string dllpath = @"E:\Workspace\ImageViewerEngine\ImageViewerEngine\x64\Debug\"
        //                + "ImageViewerEngine.dll";

        //const string dllpath = @"D:\git_destination\ImageViewerEngine\ImageViewerEngine\x64\Debug\"
        //                    +"ImageViewerEngine.dll";

        [DllImport(dllpath, EntryPoint = "ImageViewer_SaveToTiffMain", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_SaveToTiffMain(string imageFolder, string tiffPath, CallbackDelegate pCallback, int outerID);
        //初始化
        //mode 0 扫片时多文件  1扫片时单文件  2 扫完片多文件 3 扫完片单文件
        [DllImport(dllpath, EntryPoint = "ImageViewer_Init",
            CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_Init(string imageFolder, int rows, int columns, ref int sampleId, int mode);

        //给第三层数据
        [DllImport(dllpath, EntryPoint = "ImageViewer_SetSmallImageBuffer",
            CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_SetSmallImageBuffer(IntPtr buffer,
            int width, int height,
            int size, int bufferType, int row, int column, int sampleId);

        //直接dll从硬盘直接读取文件，兼容部分机器c#读取文件失效
        [DllImport(dllpath, EntryPoint = "ImageViewer_SetSmallImageBuffer2",
           CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_SetSmallImageBuffer2(int row, int column, int sampleId);

        //
        [DllImport(dllpath, EntryPoint = "ImageViewer_ScanDidEndAndDataReady",
            CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_ScanDidEndAndDataReady(int sampleId);

        [DllImport(dllpath, EntryPoint = "ImageViewer_Destroy",
            CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_Destroy(int sampleId);

        [DllImport(dllpath, EntryPoint = "ImageViewer_GetFullImageInfo",
            CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_GetFullImageInfo(ref int fullWidth, ref int fullHight, int sampleId);

        [DllImport(dllpath, EntryPoint = "ImageViewer_GetBuffer",
            CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_GetBuffer(ref Int64 bufferPtr, ref int offsetX, ref int offsetY,
            ref int width, ref int height, ref float scaleRatio, ref int preview, int sampleId);

        //释放内存
        [DllImport(dllpath, EntryPoint = "ImageViewer_FreeBuffer",
        CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_FreeBuffer(IntPtr buffer, int ID);

        [DllImport(dllpath, EntryPoint = "ImageViewer_GetBuffer_Big", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_GetBuffer_Big(ref Int64 bufferPtr, int offsetX, int offsetY, int width, int height, int sampleId);

        [DllImport(dllpath, EntryPoint = "ImageViewer_GetBuffer_Small", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_GetBuffer_Small(ref Int64 bufferPtr, ref int offsetX, ref int offsetY, ref int width, ref int height, int sampleId);

        [DllImport(dllpath, EntryPoint = "ImageViewer_GetPointPosition",
            CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_GetPointPosition(int offsetXFull, int offsetYFull, ref int row, ref int col, int sampleId);

        //根据在整个大图的位置，获取对应光栅尺
        //DLL_IMAGE_VIEWER_ENGINE_API
        [DllImport(dllpath, EntryPoint = "ImageViewer_GetRulerValueFromImagePosition", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_GetRulerValueFromImagePosition(ref int rulerX, ref int rulerY, int offsetXFull, int offsetYFull, int ID);

        //根据光栅尺，获取在整个大图的位置 2019年11月6日
        //DLL_IMAGE_VIEWER_ENGINE_API
        [DllImport(dllpath, EntryPoint = "ImageViewer_GetImagePositionFromRulerValue", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_GetImagePositionFromRulerValue(int rulerX, int rulerY, ref int offsetXFull, ref int offsetYFull, int ID);

        //返回光栅尺信息,1个光栅尺单位下的对应像素 2019年11月6日
        //DLL_IMAGE_VIEWER_ENGINE_API
        [DllImport(dllpath, EntryPoint = "ImageViewer_GetRulerInfo", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_GetRulerInfo(ref float pixelPerRulerX, ref float pixelPerRulerY, int ID);

        //根据在单张大图坐标获取在整个大图中的坐标	
        [DllImport(dllpath, EntryPoint = "ImageViewer_GetPointPositionInFullView", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_GetPointPositionInFullView(int offsetX, int offsetY, int row, int col, ref int offsetXFull, ref int offsetYFull, int sampleId);


        //根据在整个大图中的坐标获取在单张大图坐标   DLL_IMAGE_VIEWER_ENGINE_API
        [DllImport(dllpath, EntryPoint = "ImageViewer_GetPointPositionInSingleImage", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_GetPointPositionInSingleImage(ref int offsetX, ref int offsetY, int row, int col, int offsetXFull, int offsetYFull, int ID);

        //2019.03.08 leon添加
        //转成tiff文件。 scaleMax 最大尺度，level存储几层 
        //tile 256
        [DllImport(dllpath, EntryPoint = "ImageViewer_SaveToTiff", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_SaveToTiff(string tiffPath, float scaleMax, int level, int sampleId);

        [DllImport(dllpath, EntryPoint = "ImageViewer_SaveToTiff2", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_SaveToTiff2(string tiffPath, float scaleMax, int level, int offsetx, int offsety, int width, int height, int tileSizeX, int tileSizeY, int sampleId);

        //存储一张图
        [DllImport(dllpath, EntryPoint = "ImageViewer_SaveSingleImageToFile", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_SaveSingleImageToFile(string filePath, int row, int col, int sampleId);

        //输入全局图文件路径 2019年3月14日
        [DllImport(dllpath, EntryPoint = "ImageViewer_SaveSnapshotToFile", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ImageViewer_SaveSnapshotToFile(string filePath, int ID);

        public class BitmapIntPtr
        {
            public Bitmap bitmap;

            public IntPtr buffAddr;

            public BitmapIntPtr(Bitmap _bitmap, IntPtr _buffAddr)
            {
                bitmap = _bitmap;
                buffAddr = _buffAddr;
            }
        }

        public static void CloseImg(IntPtr bufPtr, int sampleId)
        {
            ImageViewer_FreeBuffer(bufPtr, sampleId);
        }

        //////////////////////////////////////////////////////////////////
        //                     请求数据
        public static BitmapIntPtr RequestImg(ref Rectangle rect, ref float ratio, ref int preview, int sampleId)
        {
            int offX = rect.X;
            int offY = rect.Y;
            int width = rect.Width;
            int height = rect.Height;

            Int64 buffAddr = 0;


            int rtn = ImageViewer_GetBuffer(ref buffAddr, ref offX, ref offY, ref width, ref height, ref ratio, ref preview, sampleId);
            if (rtn < 0 || buffAddr == 0) return null;

            // buf指针
            IntPtr bufPtr = new IntPtr(buffAddr);

            #region bufPtr Copy 
            //int length = (width + 3) / 4 * 4 * 3 * height;
            //byte[] imgBytes = new byte[length];
            //Marshal.Copy(bufPtr, imgBytes, 0, length);
            //IntPtr pObject = BytesToIntptr(imgBytes);
            //System.IO.MemoryStream ms = new System.IO.MemoryStream();
            //ms.Write(imgBytes, 0, (int)ms.Length);BytesToBitmap(imgBytes);
            //Bitmap img =  new Bitmap(width, height, (width + 3) / 4 * 4 * 3, System.Drawing.Imaging.PixelFormat.Format24bppRgb, pObject);// new IntPtr(ToInt64(imgBytes)));

            #endregion
            if (width == 0)
            {
                width = 1;
            }
            Bitmap img = new Bitmap(width, height, (width + 3) / 4 * 4 * 3, System.Drawing.Imaging.PixelFormat.Format24bppRgb, bufPtr);// new IntPtr(ToInt64(imgBytes)));
            //TODO:为180旋转
            //img.RotateFlip(RotateFlipType.Rotate180FlipNone);
            rect.X = offX;
            rect.Y = offY;
            rect.Width = width;
            rect.Height = height;


            //using (Bitmap newBitmap = new Bitmap(ii.Image_1.Width, ii.Image_1.Height))
            //{
            //    Graphics g = Graphics.FromImage(newBitmap);
            //    g.DrawImage(ii.Image_1, 0, 0, ii.Image_1.Width, ii.Image_1.Height);//透明
            //    newBitmap.Save(saveImg, System.Drawing.Imaging.ImageFormat.Jpeg);
            //    g.Dispose();
            //}

            return new BitmapIntPtr(img, bufPtr);
        }

        public static Bitmap BytesToBitmap(byte[] Bytes)
        {
            System.IO.MemoryStream stream = null;
            try
            {
                stream = new System.IO.MemoryStream(Bytes);
                Image image = Image.FromStream(stream, true);
                return new Bitmap(image);// new Bitmap(stream);
            }
            catch (ArgumentNullException ex)
            {
                string str = ex.Message;
            }
            catch (ArgumentException ex)
            {
                string str = ex.Message;
            }
            finally
            {
                stream.Close();
            }
            return null;
        }

        public static IntPtr BytesToIntptr(byte[] bytes)
        {
            int size = bytes.Length;
            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                Marshal.Copy(bytes, 0, buffer, size);
                return buffer;
            }
            catch (Exception ex)
            {
                string str = ex.Message;
                return buffer;
            }
            finally
            {
                //Marshal.FreeHGlobal(buffer);
            }
        }

        public static Bitmap RequestImgBig(ref Rectangle rect, int sampleId, int minwidth = 1000, int minheight = 1000)
        {
            int offX = rect.X;
            int offY = rect.Y;
            int width = rect.Width;
            int height = rect.Height;
            int pos = 0;
            int posCount = 0;

            Int64 buffAddr = 0;
            try
            {
                if (width > minwidth || height > minheight)
                {
                    return null;
                }
                int rtn = ImageViewer_GetBuffer_Big(ref buffAddr, offX, offY, width, height, sampleId);
                // || thumArrPtr == IntPtr.Zero
                if (rtn < 0 || buffAddr == 0) return null;

                // buf指针
                IntPtr bufPtr = new IntPtr(buffAddr);
                Bitmap img = new Bitmap(width, height, (width + 3) / 4 * 4 * 3, System.Drawing.Imaging.PixelFormat.Format24bppRgb, bufPtr);

                rect.X = offX;
                rect.Y = offY;
                rect.Width = width;
                rect.Height = height;

                return img;
            }
            catch (Exception e)
            {
                string msg = e.Message;
            }
            return null;
        }
    }
}
